package com.example.statemachine;

import com.example.statemachine.event.InitiateEvent;
import com.example.statemachine.event.UploadEvent;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.support.StaticListableBeanFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.SyncTaskExecutor;
import org.springframework.scheduling.concurrent.ConcurrentTaskScheduler;
import org.springframework.statemachine.config.EnableStateMachineFactory;
import org.springframework.statemachine.config.EnumStateMachineConfigurerAdapter;
import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer;
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
import org.springframework.statemachine.transition.TransitionConflictPolicy;

import java.util.EnumSet;
import java.util.HashSet;
import java.util.Set;


@Configuration
@EnableStateMachineFactory(name = "incomeRegistrationStateMachineConfig")
@Slf4j
@RequiredArgsConstructor
public class StateMachineConfiguration extends EnumStateMachineConfigurerAdapter<StatesEvents.State, StatesEvents.Event> {

    private static final String HOME_LOAN_APPLICATION_STATE_MACHINE = "HOME_LOAN_APPLICATION_STATE_MACHINE";

    private final InitiateEvent initiateEvent;
    private final UploadEvent uploadEvent;

    @Override
    public void configure(StateMachineConfigurationConfigurer<StatesEvents.State, StatesEvents.Event> config) throws Exception {
        config.withConfiguration().autoStartup(true).machineId(HOME_LOAN_APPLICATION_STATE_MACHINE)
                .beanFactory(new StaticListableBeanFactory()).taskExecutor(new SyncTaskExecutor())
                .taskScheduler(new ConcurrentTaskScheduler())
                .listener(new StateMachineListener())
                .transitionConflictPolicy(TransitionConflictPolicy.CHILD);
    }

    @Override
    public void configure(StateMachineStateConfigurer<StatesEvents.State, StatesEvents.Event> states) throws Exception {
        states.withStates()
                .initial(StatesEvents.State.START)
                .choice(StatesEvents.State.PENDING_DOC_CHOICE)
                .end(StatesEvents.State.SUBMITTED)
                .states(Set.of(StatesEvents.State.values()));
    }

    @Override
    public void configure(StateMachineTransitionConfigurer<StatesEvents.State, StatesEvents.Event> transitions) throws Exception {
        initiateEvent.configure(transitions);
        uploadEvent.configure(transitions);
    }
}
